package nl.ru.rd.facedetection.nnbfd.tests;

import nl.ru.rd.facedetection.nnbfd.neuralnetwork.NeuralNetwork;

/**
 * A simple test using neuralnetworks, testing their performance.
 * 
 * @author Wouter Geraedts (s0814857)
 */
public abstract class Test
{
	/**
	 * The set of inputs and outputs to train.
	 */
	protected double[][][] set;

	/**
	 * Test the performance of the network Outputs data to System.out
	 */
	public abstract void test();

	/**
	 * Learn a network one thousand times
	 * 
	 * @param network
	 *            The Network to be teached.
	 * @param learningRate
	 *            The learningrate (multiplier) by which the Network should learn.
	 */
	protected final void learn(NeuralNetwork network, double learningRate)
	{
		for(int i = 0; i < 1000; i++)
		{
			for(int j = 0; j < set.length; j++)
				network.learn(set[j][0], set[j][1], learningRate);

			System.out.println(this.check(network));
		}

		this.report(network);
	}

	/**
	 * Check the performance of the network.
	 * 
	 * @param network
	 *            The Network which needs to be checked.
	 * @return The average deviation on the learn set.
	 */
	protected final double check(NeuralNetwork network)
	{
		double result = 0.0;

		for(int i = 0; i < set.length; i++)
		{
			double[] x = network.calculate(set[i][0]);
			result += Math.abs(x[0] - set[i][1][0]);
		}

		result /= set.length;
		return result;
	}

	/**
	 * Outputs a rounded result (expectedResult vs realResult) to System.out
	 * 
	 * @param network
	 *            The Network to be reported.
	 */
	protected final void report(NeuralNetwork network)
	{
		System.out.println("----");

		for(int i = 0; i < set.length; i++)
		{
			double[] result = network.calculate(set[i][0]);
			System.out.println(set[i][1][0] + " vs " + Math.round(result[0] * 10.0) / 10.0);
		}
	}
}
